package com.woniu.zsd.shopping.service.impl;


import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.woniu.zsd.common.util.RedisKey;
import com.woniu.zsd.common.web.PageInfo;
import com.woniu.zsd.shopping.dto.SelectAllProductDto;
import com.woniu.zsd.shopping.dto.SelectCollectProductDto;
import com.woniu.zsd.shopping.model.Product;
import com.woniu.zsd.shopping.dao.ProductMapper;
import com.woniu.zsd.shopping.param.AddProductParam;
import com.woniu.zsd.shopping.param.PageParam;
import com.woniu.zsd.shopping.param.SelectProductParam;
import com.woniu.zsd.shopping.service.ProductService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhangtao
 * @since 2025年02月18日
 */
@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
    @Resource
    private ProductMapper productMapper;
    @Resource
    private RedissonClient redissonClient;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Override
    public void addProduct(AddProductParam param) throws Exception {
        QueryWrapper<Product> wrapper = new QueryWrapper<>();
        wrapper.eq("product_name", param.getProductName());
        Product product = this.getOne(wrapper);
        if (product!= null) {
            throw new Exception("商品已存在");
        }
        RLock lock = redissonClient.getFairLock(param.getProductName());
        try {
            lock.lock();
        Product newProduct = new Product();
        newProduct.setProductName(param.getProductName());
        newProduct.setProductImage(param.getProductImage());
        newProduct.setIntroduction(param.getIntroduction());
        newProduct.setDisplayName(param.getDisplayName());
        newProduct.setRequiredPoints(param.getRequiredPoints());
        newProduct.setProductTypeId(param.getProductTypeId());
        newProduct.setStockNum(100);
        newProduct.setListingTime(LocalDateTime.now());
        newProduct.setProductType("上架");
        productMapper.insert(newProduct);
        }finally {
            lock.unlock();
        }
    }

    @Override
    public void deleteProduct(Integer productId) throws Exception {
        Product product = productMapper.selectById(productId);
        if (product == null) {
            throw new Exception("商品不存在或者已删除");
        }
        RLock lock = redissonClient.getFairLock(product.getProductName());
        try {
            lock.lock();
            productMapper.deleteById(productId);
        }   finally {
            lock.unlock();
        }

    }

    @Override
    public PageInfo selectAllProduct(SelectProductParam param) throws Exception {
        //分页查询
        Page<SelectAllProductDto> dtoPage = new Page<>(param.getPageNum(), param.getPageSize());
        productMapper.selectAllProduct(dtoPage,param.getProductTypeId(),param.getProductType());
        PageInfo pageInfo = new PageInfo(dtoPage);
        return pageInfo;
    }

    @Override
    public void addProductStock(Integer productId, Integer stockNum) throws Exception {
        Product product = productMapper.selectById(productId);
        if(product == null){
            throw new Exception("商品不存在");
        }
        product.setStockNum(product.getStockNum() + stockNum);
        productMapper.updateById(product);
    }

    @Override
    public void updateProductPoint(Integer productId, Integer point) throws Exception {
        Product product = productMapper.selectById(productId);
        if(product == null){
            throw new Exception("商品不存在");
        }
        product.setRequiredPoints(point);
        productMapper.updateById(product);
    }

    @Override
    public void updateProductStatus(Integer productId, String status) throws Exception {
        Product product = productMapper.selectById(productId);
        if(product == null||product.getProductType().equals("下架")){
            throw new Exception("商品不存在或已下架");
        }
        if(product.getProductType().equals(status)){
            throw new Exception("已经是"+status+"状态,无需修改");
        }
        product.setProductType(status);
        productMapper.updateById(product);
    }


    //收藏商品
    @Override
    public void collectProduct(Integer productId, Integer userId) throws Exception {
        Product product = productMapper.selectById(productId);
        if (product == null||product.getProductType().equals("下架")) {
            throw new Exception("商品不存在或已下架");
        }
        //判断是否已经收藏
        if (stringRedisTemplate.opsForZSet().score(RedisKey.USER_COLLECT(userId), String.valueOf(productId)) != null) {
            //排序值不为空，则已经收藏
            throw new Exception("已经收藏该商品");
        }
        //添加收藏
        stringRedisTemplate.opsForZSet().add(RedisKey.USER_COLLECT(userId), String.valueOf(productId), new Date().getTime());
        //收藏后，排行榜数字自增1
        stringRedisTemplate.opsForZSet().incrementScore(RedisKey.COLLECT_RANK(), String.valueOf(productId), 1);
        productMapper.updateById(product);
    }

    @Override
    public void cancelCollectProduct(Integer productId, Integer userId) throws Exception {
        Product product = productMapper.selectById(productId);
        if (product == null||product.getProductType().equals("下架")) {
            throw new Exception("商品不存在或已下架");
        }
        //判断是否已经收藏
        if (stringRedisTemplate.opsForZSet().score(RedisKey.USER_COLLECT(userId), String.valueOf(productId)) == null) {
            //排序值为空，则未收藏
            throw new Exception("未收藏该商品");
        }
        //取消收藏
        stringRedisTemplate.opsForZSet().remove(RedisKey.USER_COLLECT(userId), String.valueOf(productId));
        //收藏后，排行榜数字自减1
        Double score = stringRedisTemplate.opsForZSet().score(RedisKey.COLLECT_RANK(), String.valueOf(productId));
        if(score > 1){
            stringRedisTemplate.opsForZSet().incrementScore(RedisKey.COLLECT_RANK(), String.valueOf(productId), -1);
        }
        if(score == 1){
            stringRedisTemplate.opsForZSet().remove(RedisKey.COLLECT_RANK(),String.valueOf(productId));
        }
    }

    //查询收藏商品
    @Override
    public PageInfo selectCollectProduct(PageParam param, Integer userId) throws Exception {
        //先查询我的集合里面收藏的商品
        Long total = stringRedisTemplate.opsForZSet().size(RedisKey.USER_COLLECT(userId));
        //计算出总页数
        long pages = total%param.getPageSize()==0?total/param.getPageSize():total/param.getPageSize()+1;
        //分页查询数据
        Integer start= (param.getPageNum()-1)*param.getPageSize();
        Integer end = param.getPageNum()*param.getPageSize()-1;
        Set<String> idList = stringRedisTemplate.opsForZSet().reverseRange(RedisKey.USER_COLLECT(userId), start, end);
        ArrayList<SelectAllProductDto> list = new ArrayList<>();
        //根据上面的idList查询商品信息
        for (String id : idList) {
            int productId = Integer.parseInt(id);
            SelectAllProductDto dto = productMapper.selectProductByproductId(productId);
            list.add(dto);
        }
        //封装分页信息
        PageInfo pageInfo = new PageInfo();
        pageInfo.setPages(pages);
        pageInfo.setTotal(total);
        pageInfo.setCurrent(Long.valueOf(param.getPageNum()));
        pageInfo.setSize(Long.valueOf(param.getPageSize()));
        pageInfo.setList(list);
        return pageInfo;
    }

    @Override
    public List<SelectCollectProductDto> selectTopTenProduct() throws Exception {
        //查询排行榜前十的商品
        Set<String> idList = stringRedisTemplate.opsForZSet().reverseRange(RedisKey.COLLECT_RANK(), 0, 9);
        ArrayList<SelectCollectProductDto> list = new ArrayList<>();
        //根据上面的idList查询商品信息
        for (String id : idList) {
            int productId = Integer.parseInt(id);
            SelectAllProductDto dto = productMapper.selectProductByproductId(productId);
            SelectCollectProductDto collectProductDto = BeanUtil.toBean(dto, SelectCollectProductDto.class);
            Double score = stringRedisTemplate.opsForZSet().score(RedisKey.COLLECT_RANK(), String.valueOf(productId));
            collectProductDto.setScore(score.intValue());
            list.add(collectProductDto);
        }
        return list;
    }

}
